#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>

#define CharDev_name "cdev"
#define CharDevClass_name "cdev_class"

static dev_t dev_no;//dev_t 设备号 32 位，其中，高12位表示主设备号，低20位表示次设备号
static struct cdev chardev_str; //字符设备结构体
static struct class *cdev_class;
static struct device* cdev_device;
static char kernel_buf[1024];



static ssize_t char_dev_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	int err;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = copy_to_user(buf, kernel_buf, size);
	return err;
}

static ssize_t char_dev_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
	int err;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = copy_from_user(kernel_buf, buf, size);
	return err;
}

static int char_dev_open (struct inode *node, struct file *file)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

static int char_dev_close (struct inode *node, struct file *file)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

static struct file_operations cdev_fops = {
	.owner	 = THIS_MODULE,
	.open    = char_dev_open,
	.read    = char_dev_read,
	.write   = char_dev_write,
	.release = char_dev_close,
};


static int __init char_dev_init(void)
{
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

    //注册一个设备
    alloc_chrdev_region(&dev_no, 0, 1, CharDev_name);//0由kernel分配；1创建一个设备
    cdev_init(&chardev_str,&cdev_fops);
    chardev_str.owner = THIS_MODULE;
    cdev_add(&chardev_str, dev_no, 1);
    //以上三句话用一句表示：
    //major = register_chrdev(0, CharDev_name, &cdev_fops);//0由kernel分配

    cdev_class = class_create(THIS_MODULE, CharDevClass_name);
    cdev_device = device_create(cdev_class, NULL, dev_no, NULL, CharDev_name);  //在/dev下有CharDev_name 设备
    return 0;

}

static void __exit char_dev_exit(void)
{
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    unregister_chrdev_region(dev_no,1);
	device_destroy(cdev_class, dev_no);
    class_destroy(cdev_class);
    
}

module_init(char_dev_init);
module_exit(char_dev_exit);

MODULE_LICENSE("GPL");